--[[
    数组模块 v1.0
    增强数组的易用性

    创建:雪月灬雪歌 2022/01/27 15:42
]]
--高频函数提前

local rawget       = rawget
local rawset       = rawset
local setmetatable = setmetatable
local getmetatable = getmetatable
local type         = type

--array通用元方法
local array_data =
    {
        type = 'array',
        _opt_del = 1, --删除当前成员
        _opt_insert = 2, --插入在当前成员前面
        _opt_add = 3, --加入到当前成员后面
    }

array = {}

--@private
--挂载array[必须要是张表]
--将table挂载上array从而伪造array
--@param t table 要挂载的表
local function array_mount(t)
    local mt = getmetatable(t)
    if mt then
        --从元表中获取元方法
        local orig = rawget(mt,"__index")
        if orig then
                --存在元表则判断index元方法 挂接array进元表
                --挂接在原元表后面 防止类表的.type 判断错误
                if type(orig) == 'function' then
                    rawset(mt, "__index",function(t,k) return orig(t,k) or array[k] end)
                elseif type(orig) == 'table' then
                    rawset(mt, "__index",function(_,k) return orig[k] or array[k] end)
                else
                    rawset(mt, "__index",function(_,k) return orig or array[k] end)
                end

        else
                --有元表 但没有元方法
                rawset(mt, "__index",function(_,k) return orig[k] or array[k] end)
        end

    else
        setmetatable(t, array_data)
    end

end

--将table 转化为 array
--@param t table 要转化的表[也可以传入其他类型变量但不推荐]
--@param force boolean 是否强制转化 忽略.type
--@return array 如果传入了表则不会创建新表而是直接转化
function array:t2a(t,force)
    if type(t) ~= 'table' then return self:new(t) end
    if t.type == 'array' then return t end
    array_mount(t)
    t[0] = table.len(t)
    return t
end

--self: class | array
--新建一个数组
--@param ... any 数组初始成员
--@return array
function array:new(...)
    local data = {...}
    local max_i =  #data
    local size = 0 --记录array大小
    local tmp = {[0] = 0}
    setmetatable(tmp, array_data)
    if max_i > 1 then
        --跳到下面的多个数据处理
    elseif max_i == 1 then  --只有一个参数 或许是table?
        if type(data[1]) == 'table' then
            tmp[0] = table.attach(tmp, data[1])
        else
            tmp[0] = 1
            tmp[1] = data[1]
        end
        return tmp
    else -- < 1 无参数
        return tmp
    end
    --多个数据：将参数传入的数据加进array
    for i=1,max_i do
        size = size + 1
        local d = data[i]
        if type(d) == 'table' then
            size = size + table.attach(tmp, d)
            tmp[0] = size
        else
            size = size + 1
            tmp[size] = d
        end
        tmp[i] = d
    end
    return tmp
end

--self: array
--向array中插入成员(相当于table.insert)
--@param pos integer 参数1:插入的位置 与table.insert相同
--@param value any 参数n:插入的值 与table.insert相同
function array:insert(...)
    table.insert(self,...)
    self[0] = self[0] + 1
end

--self: array
--从array中删除成员(相当于table.remove)
--@param pos integer 删除的位置
function array:remove(pos)
    if self[pos] then
        table.remove(self,pos)
        self[0] = self[0] - 1
    end
end


local tj = {}
--！暂时弃坑。太难了
--self: array
--ForEach遍历数组的进阶版
--@param func fun(index,value):opt,<member>
--@alias opt integer 操作项(self._opt_xxx)
--@alias member any 可选参数 只有在插入操作时有用
--通过回调函数返回的 opt 系统会自动帮你删除/向前插入/向后插入
--无返回值则无操作仅遍历
--回调中不支持其他操作 如想插入删除其他位置的成员 请自己存起来 等回调结束再进行操作
function --[[array:]]tj:foreach_opt(func)
    local index, max_index = 1, self:len()
    local value --当前遍历的值

    local offset_del, offset_insert, offset_add = 0, 0, 0
    local status, sErr, opt, member --member新成员
    --[[
        _opt_insert 前插入  后移
            | x | x |   now->new                    | tmp->x&x->now     | x |       index + 1 ; max + 1 ; offset_insert + 1 ; tmp = value(index)

        _opt_add    后插入
            | x | x |   now->value(now+1)&tmp->now  |       x           | x |       index + 1 ; max + 1 ; offset_add + 1 ; tmp = value(now)

        _opt_del 删除 后面前移
            | x | x |   now->value(now+1)           |       x           | x |       index - 1 ; max - 1 ; offset_del + 1

    ]]
    while index <= max_index do
        ----偏移值处理：删除有序表的值 同时使后面的值自动补前
        if member then
            value = member --使用新成员代替现行成员
        end
        if offset_del > 0 then
            --存在偏移值:将后面的队列前移
            value = self[ index ]
            self[ index ] = nil
            self[index - offset_del] = value
        else
            value = self[ index ]
        end
        ----遍历
        status, sErr,opt,member = xpcall(func, debug.traceback, index, value)
        if status then
            if opt == self._opt_del then --标记销毁
                --do sth.
                
            elseif opt == self._opt_insert then
                --do sth.
                
            else--if opt == self._opt_add then
                if member then
                    offset_add = offset_add + 1
                    max_index = max_index + 1
                end
            end
        else
            print("array.foreach", index, sErr)
            break
        end
        index = index + 1
    end
    
end

array.len = table.len